#ifndef MEMORY_SHARE_H
#define MEMORY_SHARE_H

#include <string>
#include <iostream>
#include <windows.h>

#define Capacity_default 921700// 640 * 480 * 3 + 100
#define Timeout_wait 100
#define Time_wait_unit 2

enum TypeMemStatus
{
    MemAvaliable = 0,
    MemIsReading = 1,
    MemIsWriting = 2,
};


class MemoryShare
{

/* usage demo, write

    std::string s = "aaaa";
    int len = s.size();

    MemoryShare memshare("demo_share", true);
    if( !memshare.init())
    {
       return 0;
    }
    if(!memshare.write(s.c_str(), len))
    {
        qDebug() << "write failed";
    }
    getchar();
    memshare.exit();

*/

/* usage demo, read

    MemoryShare memshare("demo_share", false);
    if( !memshare.init())
    {
       return 0;
    }
    int len;
    memshare.getDataLength(len);
    char* p = (char*)malloc(len*sizeof(char) + 1);
    memshare.read(p);
    p[len] = 0;
    qDebug() << p;
    getchar();
    memshare.exit();

*/

public:
    MemoryShare(const std::string& name_ = "sharedmemory", int capacity_ = Capacity_default, int timeout_wait_ = Timeout_wait);
    ~MemoryShare();

    static LPCWSTR string2LPCWSTR(std::string str);



    bool init();
    void exit();

    int getCapacity(){return capacity;}

    char* getMemPtr_data(){return p_mem + 1 + sizeof(int);}

    bool setDataLength(int len)// if init done, return val can be ignored
    {
        if(!is_init) return false;

        memcpy((p_mem + 1), &len, sizeof(int));
        return true;
    }

    bool getDataLength(int& len)// if init done, return val can be ignored
    {
        if(!is_init) return false;

        memcpy(&len, (p_mem + 1), sizeof(int));
        return true;
    }

    bool isAvaliable()// if init done, return val can be ignored
    {
        if(!is_init) return false;
        return p_mem[0] == MemAvaliable;
    }

    bool setReading(bool start)// if init done & avaliable, return val can be ignored
    {
        if(!is_init) return false;
        if (p_mem[0] != MemAvaliable)
            return false;
        p_mem[0] = start? MemIsReading : MemAvaliable;
        return true;
    }

    bool setWriting(bool start)// if init done & avaliable, return val can be ignored
    {
        if(!is_init) return false;
        if (p_mem[0] != MemAvaliable)
            return false;
        p_mem[0] = start? MemIsWriting : MemAvaliable;
        return true;
    }

    bool waitForAvailable()
    {
        if(!is_init) return false;
        int cnt = 0;
        while(p_mem[0] != MemAvaliable)
        {
            Sleep(Time_wait_unit);// 1ms
            cnt++;

            if(cnt > timeout_wait)
            {
                return false;
            }
        }
        return true;
    }

    bool write(const char* bytes, int len)
    {
        if(!is_init) return false;
        if(len > capacity) return false;
        if(!waitForAvailable())
        {
            return false;
        }

        p_mem[0] = MemIsWriting;
        memcpy((p_mem + 1), &len, sizeof(int));
        memcpy(p_mem + 1 + sizeof(int), bytes, len);
        p_mem[0] = MemAvaliable;
        return true;
    }

    bool read(char* bytes /*pre-allocated*/)
    {
        if(!is_init) return false;
        if(!waitForAvailable())
        {
            return false;
        }

        int len;
        p_mem[0] = MemIsReading;
        memcpy(&len, p_mem + 1, sizeof(int));
        if(len > capacity || len < 0)
        {
            p_mem[0] = MemAvaliable;
            return false;
        }
        memcpy(bytes, p_mem + 1 + sizeof(int), len);
        p_mem[0] = MemAvaliable;
        return true;
    }


private:
    std::string name;
    int capacity;
    bool is_init;//p_mem == nullptr

    char* p_mem;
    HANDLE h_mapfile;

    int timeout_wait;
};

#endif // MEMORY_SHARE_H
